package com.unlcn.ils.wms.backend.service.gate.impl;


import cn.huiyunche.commons.domain.PageVo;
import cn.huiyunche.commons.domain.ResultDTOWithPagination;
import cn.huiyunche.commons.exception.BusinessException;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.unlcn.ils.wms.backend.bo.gateBO.GateBO;
import com.unlcn.ils.wms.backend.bo.outboundBO.OutboundConfirmBO;
import com.unlcn.ils.wms.backend.enums.*;
import com.unlcn.ils.wms.backend.service.gate.GateControllerService;
import com.unlcn.ils.wms.backend.service.inbound.WmsCQInboundService;
import com.unlcn.ils.wms.backend.service.outbound.WmsCQOutboundService;
import com.unlcn.ils.wms.backend.service.outbound.WmsDepartureRegisterService;
import com.unlcn.ils.wms.backend.util.BrowerEncodeingUtils;
import com.unlcn.ils.wms.backend.util.HttpRequestUtil;
import com.unlcn.ils.wms.base.businessDTO.inbound.AsnOrderDTO;
import com.unlcn.ils.wms.base.dto.SysGateConfigDTO;
import com.unlcn.ils.wms.base.dto.WmsCqInboundTmsDTO;
import com.unlcn.ils.wms.base.mapper.additional.wmsOutbound.WmsPreparationPlanExtMapper;
import com.unlcn.ils.wms.base.mapper.extmapper.WmsCqinboundTmsExtMapper;
import com.unlcn.ils.wms.base.mapper.extmapper.WmsDepartureRegisterExtMapper;
import com.unlcn.ils.wms.base.mapper.extmapper.WmsShipmentPlanExtMapper;
import com.unlcn.ils.wms.base.mapper.inbound.WmsCqinboundTmsLogMapper;
import com.unlcn.ils.wms.base.mapper.inbound.WmsCqinboundTmsMapper;
import com.unlcn.ils.wms.base.mapper.outbound.WmsDepartureRegisterMapper;
import com.unlcn.ils.wms.base.mapper.sys.SysGateConfigMapper;
import com.unlcn.ils.wms.base.mapper.sys.SysUserMapper;
import com.unlcn.ils.wms.base.model.inbound.WmsCqinboundTms;
import com.unlcn.ils.wms.base.model.inbound.WmsCqinboundTmsLog;
import com.unlcn.ils.wms.base.model.outbound.WmsDepartureRegister;
import com.unlcn.ils.wms.base.model.stock.WmsShipmentPlan;
import com.unlcn.ils.wms.base.model.sys.SysGateConfig;
import com.unlcn.ils.wms.base.model.sys.SysGateConfigExample;
import com.unlcn.ils.wms.base.model.sys.SysUser;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author laishijian
 * @ClassName: GateControllerServiceImpl
 * @Description: 门控制 service impl
 * @date 2017年11月9日 上午10:12:10
 */
@Service
public class GateControllerServiceImpl implements GateControllerService {

    private final static Logger LOGGER = LoggerFactory.getLogger(GateControllerServiceImpl.class);
    @Autowired
    private WmsCQInboundService wmsCQInboundService;
    @Autowired
    private WmsDepartureRegisterService departureRegisterService;
    @Autowired
    private WmsCQOutboundService wmsCQOutboundService;
    @Autowired
    private WmsDepartureRegisterMapper wmsDepartureRegisterMapper;
    @Autowired
    private WmsDepartureRegisterExtMapper wmsDepartureRegisterExtMapper;
    @Autowired
    private SysUserMapper sysUserMapper;

    private WmsShipmentPlanExtMapper wmsShipmentPlanExtMapper;

    @Autowired
    public void setWmsShipmentPlanExtMapper(WmsShipmentPlanExtMapper wmsShipmentPlanExtMapper) {
        this.wmsShipmentPlanExtMapper = wmsShipmentPlanExtMapper;
    }

    private WmsPreparationPlanExtMapper wmsPreparationPlanExtMapper;

    @Autowired
    public void setWmsPreparationPlanExtMapper(WmsPreparationPlanExtMapper wmsPreparationPlanExtMapper) {
        this.wmsPreparationPlanExtMapper = wmsPreparationPlanExtMapper;
    }

    private WmsCqinboundTmsLogMapper wmsCqinboundTmsLogMapper;

    @Autowired
    public void setWmsCqinboundTmsLogMapper(WmsCqinboundTmsLogMapper wmsCqinboundTmsLogMapper) {
        this.wmsCqinboundTmsLogMapper = wmsCqinboundTmsLogMapper;
    }

    private WmsCqinboundTmsMapper wmsCqinboundTmsMapper;

    @Autowired
    public void setWmsCqinboundTmsMapper(WmsCqinboundTmsMapper wmsCqinboundTmsMapper) {
        this.wmsCqinboundTmsMapper = wmsCqinboundTmsMapper;
    }

    private WmsCqinboundTmsExtMapper wmsCqinboundTmsExtMapper;

    @Autowired
    public void setWmsCqinboundTmsExtMapper(WmsCqinboundTmsExtMapper wmsCqinboundTmsExtMapper) {
        this.wmsCqinboundTmsExtMapper = wmsCqinboundTmsExtMapper;
    }


    @Value("${wms.jm.gate.url}")
    private String jmGateUrl;
    @Value("${tms.pickup.host.timeoutfortracking}")
    private String propertyTime;

    private final Integer TOTAL_COUNT = 5;
    private static final Integer IN_MACNO = 2;//对应君马闸门系统入口设备机号
    private static final Integer OUT_MACNO = 1; //对应君马闸门系统出口设备机号


    /**
     * 入库闸门开启(调用tms)-hs
     * <p>
     * 2019-12-20 1.调整调用tms接口的失败与成功都向接口表中wms_cqinbound_tms表中记录数据
     * 2.调整tms闸门开启失败增加手动调用开启闸门接口web项目中
     * </p>
     *
     * @param gateBO 参数封装对象
     * @return 返回值
     */
    @Override
    public Map<String, Object> addInboundOpenToPlateNum(GateBO gateBO) {
        LOGGER.info("GateControllerServiceImpl.addInboundOpenToPlateNum gateBO: {}", gateBO);
        //校验
        String num = checkPlate(gateBO);
        //根据车牌号 获取数据---2018/1/9 bugfix 修复车牌只要在备料存在就可以进场,过滤掉已经发运的数据
        HashMap<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("num", num);
        paramMap.put("out", WmsGateControllerTypeEnum.GATE_OUT.getCode());
        paramMap.put("opened", WmsDepartureOpenStatusEnum.OPENED.getValue());
        paramMap.put("notDel", DeleteFlagEnum.NORMAL.getValue());
        paramMap.put("delType", WmsShipmentPlanModifyTypeEnum.DELETE.getValue());
        paramMap.put("orderBy", "a.sp_id desc");
        paramMap.put("start", 0);
        paramMap.put("end", 1);
        paramMap.put("whCode", WhCodeEnum.UNLCN_XN_CQ.getValue());
        //List<WmsPreparationPlan> data = wmsPreparationPlanExtMapper.selectGateInDataByVehicle(paramMap);
        //2018-1-11 bugfix 修复入场数据从备料计划中查询
        List<WmsShipmentPlan> data = wmsShipmentPlanExtMapper.selectGateInDataByVehicle(paramMap);

        Map<String, Object> resultMap = Maps.newHashMap();

        if (CollectionUtils.isNotEmpty(data)) {
            //插入到闸门记录表
            WmsShipmentPlan shipmentPlan = data.get(0);
            WmsDepartureRegister gate = new WmsDepartureRegister();
            gate.setGmtUpdate(new Date());
            gate.setGmtCreate(new Date());
            gate.setDrVehiclePlate(gateBO.getPlatenum());
            gate.setInOutType(WmsGateControllerTypeEnum.GATE_IN.getCode());
            gate.setDrOpenStatus(WmsDepartureOpenStatusEnum.OPENED.getValue());
            gate.setDrDepartureType(WmsDepartureTypeEnum.TMS_SUCCESS.getValue());
            gate.setDrDepartureTime(new Date());
            gate.setDispatchNo(shipmentPlan.getSpDispatchNo());
            gate.setCreateUserName(null);
            gate.setModifyUserName(null);
            gate.setWhCode(WhCodeEnum.UNLCN_XN_CQ.getValue());
            wmsDepartureRegisterMapper.insertSelective(gate);
            resultMap.put("result", "success");
            resultMap.put("msg", "闸门开启");
        } else {
            //调用TMS
            HashMap<String, Object> tmsResultMap = wmsCQInboundService.saveInboundDetailByVehicleFromTms(num, gateBO.getPlatenum(), null);
            //有结果
            String success = tmsResultMap.get("success").toString();
            //如果调用成功
            if ("true".equals(success)) {
                resultMap.put("result", "success");
                resultMap.put("msg", tmsResultMap.get("message"));
            } else {
                resultMap.put("result", "failed");
                resultMap.put("msg", tmsResultMap.get("message"));
            }
        }
        return resultMap;
    }

    /**
     * 校验并返回车牌
     *
     * @param gateBO 参数封装对象
     * @return 返回值
     */
    private String checkPlate(GateBO gateBO) {
        if (StringUtils.isBlank(gateBO.getPlatenum())) {
            throw new BusinessException("车牌号不能为空");
        }

        String num = gateBO.getPlatenum();

        //判断是否有汉字
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(num);
        if (m.find()) {
            num = "%" + num.substring(1, num.length());
        } else {
            num = "%" + num;
        }
        return num;
    }

    /**
     * 保存板车离场记录
     *
     * @param plateNum 车牌号
     * @throws Exception 抛出异常
     */
    private void addDepartureRegister(String plateNum) throws Exception {
        WmsDepartureRegister wmsDepartureRegister = new WmsDepartureRegister();
        wmsDepartureRegister.setDrVehiclePlate(plateNum);//车牌号
        wmsDepartureRegister.setDrOpenStatus(WmsDepartureOpenStatusEnum.NOT_OPEN.getValue());//开闸状态
        wmsDepartureRegister.setGmtCreate(new Date());//创建时间
        departureRegisterService.addDeparture(wmsDepartureRegister);
    }


    /**
     * <p>
     * 君马入场闸门开启
     * 2018-1-9 新增功能：君马闸门开启
     * </p>
     *
     * @throws Exception 异常抛出
     */
    @Override
    public void updateJmGateIn(AsnOrderDTO asnOrderDTO) throws Exception {
        LOGGER.info("GateControllerServiceImpl.updateJmGateIn params:{}", JSONObject.toJSONString(asnOrderDTO));
        String result = null;
        String oddVin = asnOrderDTO.getAsnOrderDetailDTOList().get(0).getOddVin();
        Map<String, Object> params = new HashMap<>();
        Map<String, Object> headerMap = new HashMap<>();
        params.put("CardNo", StringUtils.isBlank(oddVin) ? "" : oddVin);
        //todo 需要配置闸门的控制机设备机号
        params.put("MacNo", IN_MACNO);
        //查询数据库君马闸门服务地址
        SysGateConfigExample configExample = new SysGateConfigExample();
        configExample.setOrderByClause("id desc");
        configExample.setLimitStart(0);
        configExample.setLimitEnd(1);
        configExample.createCriteria().andWhCodeEqualTo(WhCodeEnum.JM_CS.getValue())
                .andIsDeleteEqualTo((int) DeleteFlagEnum.NORMAL.getValue());
        List<SysGateConfig> sysGateConfigs = sysGateConfigMapper.selectByExample(configExample);
        String url = null;
        if (CollectionUtils.isNotEmpty(sysGateConfigs)) {
            SysGateConfig sysGateConfig = sysGateConfigs.get(0);
            url = sysGateConfig.getChannel();
        }
        params.put("url", url);
        try {
            result = updateCallJmGate(params, headerMap);
        } catch (Exception e) {
            LOGGER.error("GateControllerServiceImpl.updateJmGateIn 调用闸门开启系统超时失败");
            result = "{\n" +
                    "    \"Code\": 0,\n" +
                    "    \"ErrMsg\": \"调用tms接口超时失败!\"\n" +
                    "}";
            //插入入场失败记录
            WmsDepartureRegister register = getFailWmsDepartureRegister(oddVin);
            wmsDepartureRegisterMapper.insertSelective(register);
            //日志
            WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
            wmsCqinboundTmsLogMapper.insertSelective(log);
            //wms本地记录
            WmsCqinboundTms data = getWmsCqinboundTms(oddVin);
            wmsCqinboundTmsMapper.insertSelective(data);
            //再循环计划的调用接口4次
            updateScheduleFomJmGateIn(params, headerMap, register);

        }
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            Integer code = jsonObject.getInteger("Code");
            String errMsg = jsonObject.getString("ErrMsg");
            if (code == 0) {
                //开门成功
                LOGGER.info("GateControllerServiceImpl.updateJmGateIn 开门成功 二维码车架号 vin:{}", oddVin);
                //更新入场记录成功
                WmsDepartureRegister register = getFailWmsDepartureRegister(oddVin);
                register.setDrOpenStatus(WmsDepartureOpenStatusEnum.OPENED.getValue());
                register.setDrDepartureType(WmsDepartureTypeEnum.TMS_SUCCESS.getValue());
                register.setDrDepartureTime(new Date());
                wmsDepartureRegisterMapper.insertSelective(register);
                //日志
                WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                log.setTmsResult(String.valueOf(Boolean.TRUE));
                wmsCqinboundTmsLogMapper.insertSelective(log);
                //wms本地记录
                WmsCqinboundTms data = getWmsCqinboundTms(oddVin);
                data.setTmsResult(String.valueOf(Boolean.TRUE));
                wmsCqinboundTmsMapper.insertSelective(data);
            } else {
                //开门失败
                LOGGER.error("GateControllerServiceImpl.updateJmGateIn 调用闸门开启系统失败 error:" + errMsg);
                //插入入场失败记录
                WmsDepartureRegister register = getFailWmsDepartureRegister(oddVin);
                wmsDepartureRegisterMapper.insertSelective(register);
                //日志
                WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                wmsCqinboundTmsLogMapper.insertSelective(log);
                //wms本地记录
                WmsCqinboundTms data = getWmsCqinboundTms(oddVin);
                wmsCqinboundTmsMapper.insertSelective(data);
                //再循环计划的调用接口4次
                updateScheduleFomJmGateIn(params, headerMap, register);
            }
        }
    }

    /**
     * 出场闸门开启---君马库
     * <p>
     * 2018-1-9 新增功能：君马闸门开启
     * </p>
     *
     * @param sysUser 用户 可能为空
     * @param bo      出场参数封装
     * @throws Exception 异常
     */
    @Override
    public void updateJmGateOut(SysUser sysUser, OutboundConfirmBO bo) throws Exception {
        LOGGER.info("GateControllerServiceImpl.updateJmGateOut params:{}", JSONObject.toJSONString(bo));
        String result = null;
        String orderNo = bo.getOrderNo();
        String vin = bo.getVin();
        Map<String, Object> params = new HashMap<>();
        Map<String, Object> headerMap = new HashMap<>();
        params.put("CardNo", StringUtils.isBlank(vin) ? "" : vin);
        //todo 需要配置闸门的控制机设备机号
        params.put("MacNo", OUT_MACNO);
        //查询数据库君马闸门服务地址
        SysGateConfigExample configExample = new SysGateConfigExample();
        configExample.setOrderByClause("id desc");
        configExample.setLimitStart(0);
        configExample.setLimitEnd(1);
        configExample.createCriteria().andWhCodeEqualTo(WhCodeEnum.JM_CS.getValue())
                .andIsDeleteEqualTo((int) DeleteFlagEnum.NORMAL.getValue());
        List<SysGateConfig> sysGateConfigs = sysGateConfigMapper.selectByExample(configExample);
        String url = null;
        if (CollectionUtils.isNotEmpty(sysGateConfigs)) {
            SysGateConfig sysGateConfig = sysGateConfigs.get(0);
            url = sysGateConfig.getChannel();
        }
        params.put("url", url);
        try {
            result = updateCallJmGate(params, headerMap);
        } catch (Exception e) {
            LOGGER.error("GateControllerServiceImpl.updateJmGateOut 调用闸门开启系统超时失败");
            result = "{\n" +
                    "    \"Code\": 0,\n" +
                    "    \"ErrMsg\": \"调用tms接口超时失败!\"\n" +
                    "}";
            //插入入场失败记录
            WmsDepartureRegister register = getFailWmsDepartureRegister(vin);
            register.setInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
            register.setDispatchNo(orderNo);   //使用出场的调度指令号字段存储君马库的出库单号
            wmsDepartureRegisterMapper.insertSelective(register);
            //日志
            WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
            log.setTmsInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
            wmsCqinboundTmsLogMapper.insertSelective(log);
            //wms本地记录
            WmsCqinboundTms data = getWmsCqinboundTms(vin);
            data.setWmsInOutStatus(WmsGateControllerTypeEnum.GATE_OUT.getCode());
            data.setDispatchNo(orderNo);
            wmsCqinboundTmsMapper.insertSelective(data);
            //再循环计划的调用接口4次
            updateScheduleFomJmGateIn(params, headerMap, register);

        }
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            Integer code = jsonObject.getInteger("Code");
            String errMsg = jsonObject.getString("ErrMsg");
            if (code == 0) {
                //开门成功
                LOGGER.info("GateControllerServiceImpl.updateJmGateOut 开门成功 二维码车架号 vin:{}", vin);
                //更新入场记录成功
                WmsDepartureRegister register = getFailWmsDepartureRegister(vin);
                register.setDrOpenStatus(WmsDepartureOpenStatusEnum.OPENED.getValue());
                register.setDrDepartureType(WmsDepartureTypeEnum.TMS_SUCCESS.getValue());
                register.setDrDepartureTime(new Date());
                register.setInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                register.setDispatchNo(orderNo);   //使用出场的调度指令号字段存储君马库的出库单号
                wmsDepartureRegisterMapper.insertSelective(register);
                //日志
                WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                log.setTmsResult(String.valueOf(Boolean.TRUE));
                log.setTmsInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                wmsCqinboundTmsLogMapper.insertSelective(log);
                //wms本地记录
                WmsCqinboundTms data = getWmsCqinboundTms(vin);
                data.setTmsResult(String.valueOf(Boolean.TRUE));
                data.setWmsInOutStatus(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                data.setDispatchNo(orderNo);
                wmsCqinboundTmsMapper.insertSelective(data);
            } else {
                //开门失败
                LOGGER.error("GateControllerServiceImpl.updateJmGateOut 调用闸门开启系统失败 error:" + errMsg);
                //插入入场失败记录
                WmsDepartureRegister register = getFailWmsDepartureRegister(vin);
                register.setInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                register.setDispatchNo(orderNo);   //使用出场的调度指令号字段存储君马库的出库单号
                wmsDepartureRegisterMapper.insertSelective(register);
                //日志
                WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                log.setTmsInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                wmsCqinboundTmsLogMapper.insertSelective(log);
                //wms本地记录
                WmsCqinboundTms data = getWmsCqinboundTms(vin);
                data.setWmsInOutStatus(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                data.setDispatchNo(orderNo);
                wmsCqinboundTmsMapper.insertSelective(data);
                //再循环计划的调用接口4次
                updateScheduleFomJmGateOut(params, headerMap, register);
            }
        }
    }

    /**
     * <p>
     * 2018-1-25 查找君马仓库闸门服务url地址
     * </p>
     *
     * @param whCode 仓库code
     * @throws Exception 异常
     */

    @Override
    public List<SysGateConfig> getJmGateUrl(String whCode) throws Exception {
        LOGGER.info("WmsGateOpenController.getChannel param:{}", whCode);
        if (StringUtils.isBlank(whCode))
            throw new BusinessException("仓库code为空!");
        if (!(WhCodeEnum.JM_CS.getValue().equals(whCode) || WhCodeEnum.JM_XY.getValue().equals(whCode)))
            throw new BusinessException("该仓库不支持此操作!");
        SysGateConfigExample example = new SysGateConfigExample();
        example.createCriteria().andIsDeleteEqualTo((int) DeleteFlagEnum.NORMAL.getValue())
                .andWhCodeEqualTo(whCode);
        return sysGateConfigMapper.selectByExample(example);
    }

    /**
     * <p>
     * 2018-1-25 该接口用于更新君马仓库闸门服务url地址
     * </p>
     *
     * @param dto 参数封装
     * @throws Exception 异常
     */
    @Override
    public void updateJmGateUrl(SysGateConfigDTO dto) throws Exception {
        LOGGER.info("WmsGateOpenController.updateJmGateUrl param:{}", dto);
        if (Objects.equals(dto, null))
            throw new BusinessException("传入参数不能为空!");
        if (StringUtils.isBlank(dto.getChannel()))
            throw new BusinessException("url地址不能为空!");
        if (StringUtils.isBlank(dto.getId()))
            throw new BusinessException("id不能为空!");
        String whCode = dto.getWhCode();
        if (StringUtils.isBlank(whCode))
            throw new BusinessException("仓库code不能为空!");
        if (!(WhCodeEnum.JM_CS.getValue().equals(whCode) || WhCodeEnum.JM_XY.getValue().equals(whCode)))
            throw new BusinessException("该仓库不支持此操作!");
        SysGateConfig config = new SysGateConfig();
        config.setChannel(dto.getChannel());
        config.setId(Integer.valueOf(dto.getId()));
        sysGateConfigMapper.updateByPrimaryKeySelective(config);
    }

    /**
     * 再重复调用君马闸门系统4次 直至成功
     *
     * @param params    闸门系统传入的参数
     * @param headerMap 接口调用请求头
     * @param register  用于闸门系统的状态更新 失败-->成功
     */
    private void updateScheduleFomJmGateOut(Map<String, Object> params, Map<String, Object> headerMap, WmsDepartureRegister register) {
        LOGGER.info("GateControllerServiceImpl.updateScheduleFomJmGateOut param:{} ", JSONObject.toJSONString(params));
        //查询最后一次的失败记录
        String vin = params.get("CardNo").toString();
        HashMap<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("orderBy", "id desc");
        paramMap.put("gateOut", WmsGateControllerTypeEnum.GATE_OUT.getCode());
        paramMap.put("start", 0);
        paramMap.put("end", 1);
        paramMap.put("whCode", WhCodeEnum.JM_CS.getValue());
        paramMap.put("notDel", DeleteFlagEnum.NORMAL.getValue());
        paramMap.put("vin", vin);
        List<WmsCqinboundTms> list = wmsCqinboundTmsExtMapper.selectLastGateOutFailDataByParam(paramMap);
        if (CollectionUtils.isNotEmpty(list)) {
            WmsCqinboundTms data = list.get(0);
            while (String.valueOf(Boolean.FALSE).equals(data.getTmsResult()) &&
                    data.getTmsInnvocationCount() < TOTAL_COUNT) {
                data.setTmsInnvocationCount(data.getTmsInnvocationCount() + 1);
                String result = null;
                try {
                    result = updateCallJmGate(params, headerMap);
                    if (StringUtils.isNotBlank(result)) {
                        JSONObject jsonObject = JSONObject.parseObject(result);
                        Integer code = jsonObject.getInteger("Code");
                        String errMsg = jsonObject.getString("ErrMsg");
                        if (code == 0) {
                            //开门成功
                            LOGGER.info("GateControllerServiceImpl.updateScheduleFomJmGateOut 开门成功 二维码车架号 vin:{}", vin);
                            //日志
                            WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                            log.setTmsResult(String.valueOf(Boolean.TRUE));
                            log.setTmsInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                            log.setTmsMsg("出场闸门开启成功");
                            wmsCqinboundTmsLogMapper.insertSelective(log);
                            //wms本地记录
                            data.setTmsResult(String.valueOf(Boolean.TRUE));
                            wmsCqinboundTmsMapper.insertSelective(data);
                            //更新离场的记录
                            register.setDrDepartureTime(new Date());
                            register.setDrOpenStatus(WmsDepartureOpenStatusEnum.OPENED.getValue());
                            register.setDrDepartureType(WmsDepartureTypeEnum.TMS_SUCCESS.getValue());
                            wmsDepartureRegisterMapper.updateByPrimaryKey(register);
                            break;
                        } else {
                            //开门失败
                            LOGGER.error("GateControllerServiceImpl.updateScheduleFomJmGateOut 调用闸门开启系统失败 error:" + errMsg);
                            //日志
                            WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                            wmsCqinboundTmsLogMapper.insertSelective(log);
                            //wms本地记录
                            wmsCqinboundTmsMapper.insertSelective(data);
                        }
                    }
                } catch (Exception e) {
                    LOGGER.error("GateControllerServiceImpl.updateScheduleFomJmGateOut 再计划调用君马闸门系统失败 error:");
                    result = "{\n" +
                            "    \"Code\": 0,\n" +
                            "    \"ErrMsg\": \"调用tms接口超时失败!\"\n" +
                            "}";
                    //日志
                    WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                    wmsCqinboundTmsLogMapper.insertSelective(log);
                    //wms本地记录
                    wmsCqinboundTmsMapper.insertSelective(data);
                }
            }
        }
    }

    /**
     * 再重复调用君马闸门系统4次 直至成功
     *
     * @param params    闸门系统传入的参数
     * @param headerMap 接口调用请求头
     * @param register  用于闸门系统的状态更新 失败-->成功
     */
    private void updateScheduleFomJmGateIn(Map<String, Object> params, Map<String, Object> headerMap, WmsDepartureRegister register) {
        LOGGER.info("GateControllerServiceImpl.updateScheduleFomJmGateIn param:{} ", JSONObject.toJSONString(params));
        //查询最后一次的失败记录
        String vin = params.get("CardNo").toString();
        HashMap<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("orderBy", "id desc");
        paramMap.put("gateIn", WmsGateControllerTypeEnum.GATE_IN.getCode());
        paramMap.put("start", 0);
        paramMap.put("end", 1);
        paramMap.put("whCode", WhCodeEnum.JM_CS.getValue());
        paramMap.put("notDel", DeleteFlagEnum.NORMAL.getValue());
        paramMap.put("vin", vin);
        List<WmsCqinboundTms> list = wmsCqinboundTmsExtMapper.selectLastGateInFailDataByParam(paramMap);
        if (CollectionUtils.isNotEmpty(list)) {
            WmsCqinboundTms data = list.get(0);
            while (String.valueOf(Boolean.FALSE).equals(data.getTmsResult()) &&
                    data.getTmsInnvocationCount() < TOTAL_COUNT) {
                data.setTmsInnvocationCount(data.getTmsInnvocationCount() + 1);
                String result = null;
                try {
                    result = updateCallJmGate(params, headerMap);
                    if (StringUtils.isNotBlank(result)) {
                        JSONObject jsonObject = JSONObject.parseObject(result);
                        Integer code = jsonObject.getInteger("Code");
                        String errMsg = jsonObject.getString("ErrMsg");
                        if (code == 0) {
                            //开门成功
                            LOGGER.info("GateControllerServiceImpl.updateScheduleFomJmGateIn 开门成功 二维码车架号 vin:{}", vin);
                            //日志
                            WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                            log.setTmsResult(String.valueOf(Boolean.TRUE));
                            log.setTmsMsg("入场闸门开启成功");
                            wmsCqinboundTmsLogMapper.insertSelective(log);
                            //wms本地记录
                            data.setTmsResult(String.valueOf(Boolean.TRUE));
                            wmsCqinboundTmsMapper.insertSelective(data);
                            //更新离场的记录
                            register.setDrDepartureTime(new Date());
                            register.setDrOpenStatus(WmsDepartureOpenStatusEnum.OPENED.getValue());
                            register.setDrDepartureType(WmsDepartureTypeEnum.TMS_SUCCESS.getValue());
                            wmsDepartureRegisterMapper.updateByPrimaryKey(register);
                            break;
                        } else {
                            //开门失败
                            LOGGER.error("GateControllerServiceImpl.updateScheduleFomJmGateIn 调用闸门开启系统失败 error:" + errMsg);
                            //日志
                            WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                            log.setTmsInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                            wmsCqinboundTmsLogMapper.insertSelective(log);
                            //wms本地记录
                            wmsCqinboundTmsMapper.insertSelective(data);
                        }
                    }

                } catch (Exception e) {
                    LOGGER.error("GateControllerServiceImpl.updateScheduleFomJmGateIn 再计划调用君马闸门系统失败 error:");
                    result = "{\n" +
                            "    \"Code\": 0,\n" +
                            "    \"ErrMsg\": \"调用tms接口超时失败!\"\n" +
                            "}";
                    //日志
                    WmsCqinboundTmsLog log = getFailWmsCqinboundTmsLog(result, params);
                    wmsCqinboundTmsLogMapper.insertSelective(log);
                    //wms本地记录
                    wmsCqinboundTmsMapper.insertSelective(data);
                }
            }
        }
    }

    /**
     * 用于接口失败的时候次数记录
     *
     * @param oddVin 车架号
     * @return 返回值
     */
    private WmsCqinboundTms getWmsCqinboundTms(String oddVin) {
        WmsCqinboundTms data = new WmsCqinboundTms();
        data.setWmsInOutStatus(WmsGateControllerTypeEnum.GATE_IN.getCode());
        data.setGmtCreate(new Date());
        data.setTmsResult(String.valueOf(Boolean.FALSE));
        data.setVin(oddVin);
        data.setWhCode(WhCodeEnum.JM_CS.getValue());
        data.setIsDelete(DeleteFlagEnum.NORMAL.getValue());
        data.setWhName(WhCodeEnum.JM_CS.getText());
        data.setTmsInnvocationCount(1);
        return data;
    }

    private SysGateConfigMapper sysGateConfigMapper;

    @Autowired
    public void setSysGateConfigMapper(SysGateConfigMapper sysGateConfigMapper) {
        this.sysGateConfigMapper = sysGateConfigMapper;
    }


    /**
     * 插入失败记录的接口日志
     *
     * @param result 接口返回结果
     * @param params 传入接口参数
     * @return 返回值
     */
    private WmsCqinboundTmsLog getFailWmsCqinboundTmsLog(String result, Map<String, Object> params) {
        WmsCqinboundTmsLog log = new WmsCqinboundTmsLog();
        String url = (String) params.get("url");
        log.setTmsUrl(url);
        if (StringUtils.isBlank(url)) {
            log.setTmsUrl(jmGateUrl + "/ParkingService.aspx");
        }
        log.setTmsParam("{" +
                "CardNo:" + params.get("CardNo") +
                ",MacNo:" + params.get("MacNo") +
                "}");
        log.setTmsResult(String.valueOf(Boolean.FALSE));
        SimpleDateFormat miSdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        log.setTmsInvocationTimestamp(Long.valueOf(miSdf.format(new Date())));
        log.setTmsInOutType(WmsGateControllerTypeEnum.GATE_IN.getCode());
        log.setTmsMsg(result);
        log.setCreateTime(new Date());
        return log;
    }

    /**
     * 插入出入场记录
     *
     * @param oddVin 车架号
     * @return 返回值
     */
    private WmsDepartureRegister getFailWmsDepartureRegister(String oddVin) {
        WmsDepartureRegister register = new WmsDepartureRegister();
        register.setWhCode(WhCodeEnum.JM_CS.getValue());
        register.setDrDepartureType(WmsDepartureTypeEnum.TMS_FAILED.getValue());
        register.setDrVehiclePlate(oddVin);
        register.setGmtCreate(new Date());
        register.setGmtUpdate(new Date());
        register.setDrOpenStatus(WmsDepartureOpenStatusEnum.NOT_OPEN.getValue());
        register.setInOutType(WmsGateControllerTypeEnum.GATE_IN.getCode());
        return register;
    }

    /**
     * 调用君马开门的远程接口
     *
     * @return 返回值json格式
     */
    private String updateCallJmGate(Map<String, Object> params, Map<String, Object> headerMap) {
        String url = (String) params.get("url");
        if (StringUtils.isBlank(url)) {
            url = jmGateUrl + "/ParkingSevice.aspx";
        }
        headerMap.put("Content-Type", "application/x-www-form-urlencoded");
        //Integer time = Integer.parseInt(propertyTime);
        String result = null;
        try {
            result = HttpRequestUtil.httpURLConnectionPOST(url, JSONObject.toJSONString(params));
            //String s = HttpRequestUtil.sendHttpPost(url, headerMap, params, time);
        } catch (Exception e) {
            throw new BusinessException("调用tms接口超时失败!");
        }
        return result;
    }

    /**
     * <p>
     * --2018/12/28 新需求 出场闸门开启过慢,tms结果不影响闸门的开启状态
     * --2018/1/9 新需求 以tms接口控制板车是否装车完成及是否打印出场单据控制闸门开启
     * </p>
     * 板车出场  系统判断自动开闸门
     *
     * @param gateBO 参数封装 //车牌号
     * @return 返回值
     */
    @Override
    public Map<String, Object> updateOutboundOpenToPlateNum(GateBO gateBO) {
        LOGGER.info("GateControllerServiceImpl.updateOutboundOpenToPlateNum gateBO: {}", new Gson().toJson(gateBO));
        //校验
        String num = checkPlate(gateBO);
        Map<String, Object> resultMap = Maps.newHashMap();
        //根据车牌号 获取数据---2018/1/9 bugfix 修复车牌只要在备料存在就可以出场,过滤掉已经发运的数据
        HashMap<String, Object> params = Maps.newHashMap();
        params.put("num", num);
        params.put("out", WmsGateControllerTypeEnum.GATE_OUT.getCode());
        params.put("in", WmsGateControllerTypeEnum.GATE_IN.getCode());
        params.put("opened", WmsDepartureOpenStatusEnum.OPENED.getValue());
        params.put("delType", WmsShipmentPlanModifyTypeEnum.DELETE.getValue());
        params.put("whCode", WhCodeEnum.UNLCN_XN_CQ.getValue());
        params.put("orderBy", "a.sp_id desc");
        params.put("start", 0);
        params.put("end", 1);
        List<WmsShipmentPlan> plans = wmsShipmentPlanExtMapper.selectGateOutDataByVehicle(params);
        if (!plans.isEmpty()) {
            //找到发运计划 直接开闸
            WmsShipmentPlan wmsShipmentPlan = plans.get(0);    //取最新的数据
            //resultMap.put("result", "success");
            //resultMap.put("msg", "闸门开启");
            //调用接口 tms  --2018/1/9 新需求 以tms接口控制板车是否装车完成及是否打印出场单据控制闸门开启
            Map<String, Object> tmsResult = wmsCQOutboundService.saveOutboundDetailByVehicleFromTms(wmsShipmentPlan.getSpWhName(), wmsShipmentPlan.getSpSupplierVehiclePlate(), wmsShipmentPlan.getSpDispatchNo());
            if (String.valueOf(Boolean.TRUE).equals(tmsResult.get("success").toString())) {
                resultMap.put("result", "success");
                resultMap.put("msg", "闸门开启");
            } else {
                resultMap.put("result", "failed");
                resultMap.put("msg", tmsResult.get("message").toString());
            }
        } else {
            //没找到发运计划  查找是否存在入场记录  存在也开闸
            // 2018/1/9  bugfix --也要限制以前出入的数据
            List<WmsDepartureRegister> registers = wmsDepartureRegisterExtMapper.selectGateOutDataByParam(params);

            WmsDepartureRegister outRegister = new WmsDepartureRegister();
            outRegister.setGmtUpdate(new Date());
            outRegister.setGmtCreate(new Date());
            outRegister.setDrVehiclePlate(gateBO.getPlatenum());
            outRegister.setInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());

            if (CollectionUtils.isNotEmpty(registers)) {
                //找到了入库的记录直接开启闸门
                resultMap.put("result", "success");
                resultMap.put("msg", "闸门开启");
                //更新插入出场闸门开启记录
                outRegister.setDrOpenStatus(WmsDepartureOpenStatusEnum.OPENED.getValue());
                outRegister.setDrDepartureType(WmsDepartureTypeEnum.TMS_SUCCESS.getValue());
            } else {
                //没有找到入库的记录直接开启闸门
                resultMap.put("result", "failed");
                resultMap.put("msg", "未查询到对应入场记录及发运指令,请手动开闸");
                //更新插入出场闸门开启记录
                outRegister.setDrOpenStatus(WmsDepartureOpenStatusEnum.NOT_OPEN.getValue());
                outRegister.setDrDepartureType(WmsDepartureTypeEnum.TMS_FAILED.getValue());
            }
            outRegister.setWhCode(WhCodeEnum.UNLCN_XN_CQ.getValue());
            //插入前进行重复校验
            //去除重复  --有当天的失败记录就不插入数据
            if (WmsDepartureOpenStatusEnum.NOT_OPEN.getValue() == outRegister.getDrOpenStatus()) {
                HashMap<String, Object> paramMap = Maps.newHashMap();
                paramMap.put("vehicle", gateBO.getPlatenum());
                paramMap.put("inOut", WmsGateControllerTypeEnum.GATE_OUT.getCode());
                paramMap.put("notOpen", WmsDepartureOpenStatusEnum.NOT_OPEN.getValue());
                paramMap.put("result", WmsDepartureTypeEnum.TMS_FAILED.getValue());
                List<WmsDepartureRegister> list = wmsDepartureRegisterExtMapper.selectTodayData(paramMap);
                if (CollectionUtils.isEmpty(list)) {
                    wmsDepartureRegisterMapper.insertSelective(outRegister);
                }
            } else {
                //成功  不去重
                wmsDepartureRegisterMapper.insertSelective(outRegister);
            }

        }
        return resultMap;
    }


    /**
     * 查询闸门开启失败的记录
     *
     * @param dto    参数对象
     * @param userId 用户id
     * @param whCode 仓库code
     * @throws Exception 异常
     */
    @Override
    public ResultDTOWithPagination<List<WmsDepartureRegister>> getFailedOpenList(WmsCqInboundTmsDTO dto, String userId, String whCode) throws Exception {
        LOGGER.info("GateControllerServiceImpl.getFailedOpenList param:{},{}", userId, whCode);
        if (Objects.equals(dto, null))
            throw new BusinessException("传入参数不能为空!");
        if (StringUtils.isBlank(userId))
            throw new BusinessException("用户id不能为空!");
        if (StringUtils.isBlank(whCode))
            throw new BusinessException("仓库code不能为空!");
        if (!WhCodeEnum.UNLCN_XN_CQ.getValue().equals(whCode))
            throw new BusinessException("该仓库不支持此操作!");
        ResultDTOWithPagination<List<WmsDepartureRegister>> result = new ResultDTOWithPagination<>();
        HashMap<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("whCode", whCode);
        paramMap.put("start", dto.getStartIndex());
        paramMap.put("end", dto.getPageSize());
        paramMap.put("orderBy", StringUtils.isBlank(dto.getOrder()) ? "dr_id desc" : dto.getOrder());
        paramMap.put("status", dto.getStatus());
        paramMap.put("type", StringUtils.isBlank(dto.getDepartureType()) ? WmsDepartureTypeEnum.TMS_FAILED.getValue() : dto.getDepartureType());
        paramMap.put("vehicle", dto.getVehicle());
        paramMap.put("startTime", dto.getStartDeparturTime());
        paramMap.put("endTime", dto.getEndDepartureTime());
        paramMap.put("inoutType", StringUtils.isBlank(dto.getDepartureInOutType()) ? "" : dto.getDepartureInOutType());
        List<WmsDepartureRegister> list = wmsDepartureRegisterExtMapper.selectListByParam(paramMap);
        int count = wmsDepartureRegisterExtMapper.selectListCountByParam(paramMap);
        result.setData(list);
        PageVo pageVo = new PageVo();
        pageVo.setPageNo(dto.getPageNo());
        pageVo.setTotalRecord(count);
        pageVo.setOrder(dto.getOrder());
        pageVo.setPageSize(dto.getPageSize());
        result.setPageVo(pageVo);
        return result;
    }

    /**
     * 用于系统闸门开启失败后手动开启
     *
     * @param dto    板车车牌号
     * @param userId 用户id
     * @param whCode 仓库code
     * @throws Exception 抛出异常
     */
    @Override
    public void addOpenByHm(WmsCqInboundTmsDTO dto, String userId, String whCode) throws Exception {
        LOGGER.info("GateControllerServiceImpl.addOpenByHm param:{},{},{}", dto, userId, whCode);
        if (Objects.equals(dto, null))
            throw new BusinessException("参数不能为空!");
        if (StringUtils.isBlank(dto.getDrId()))
            throw new BusinessException("记录id不能为空!");
        if (StringUtils.isBlank(dto.getDepartureReason()))
            throw new BusinessException("请选择手动开启闸门的原因");
        if (StringUtils.isBlank(userId))
            throw new BusinessException("用户id不能为空!");
        if (StringUtils.isBlank(whCode))
            throw new BusinessException("仓库code不能为空!");
        if (!WhCodeEnum.UNLCN_XN_CQ.getValue().equals(whCode))
            throw new BusinessException("该仓库不支持此操作!");
        //看是哪种类型的出入库闸门开启
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(Integer.valueOf(userId));
        //更新记录到出场记录中
        WmsDepartureRegister departureRegister = wmsDepartureRegisterMapper.selectByPrimaryKey(Long.valueOf(dto.getDrId()));
        if (!Objects.equals(departureRegister, null)) {
            departureRegister.setModifyUserName(sysUser.getName());
            departureRegister.setGmtUpdate(new Date());
            departureRegister.setDrDepartureTime(new Date());
            departureRegister.setDrOpenStatus(WmsDepartureOpenStatusEnum.OPENED.getValue());
            departureRegister.setDrDepartureType(WmsDepartureTypeEnum.WMS_HAND.getValue());
            departureRegister.setDrDepartureReason(dto.getDepartureReason());
            wmsDepartureRegisterMapper.updateByPrimaryKeySelective(departureRegister);
            if (WmsGateControllerTypeEnum.GATE_IN.getCode().equals(departureRegister.getInOutType())) {
                wmsCQInboundService.addInboundOpenByHm(departureRegister, dto, sysUser, whCode);
            }
            if (WmsGateControllerTypeEnum.GATE_OUT.getCode().equals(departureRegister.getInOutType())) {
                wmsCQOutboundService.addOutboundOpenByHm(dto, sysUser, whCode, departureRegister);
            }
        }
    }

    /**
     * @param dto
     * @param request
     * @param response
     * @throws Exception
     */
    @Override
    public void gateRecordsImpotExcel(WmsCqInboundTmsDTO dto, HttpServletRequest request, HttpServletResponse response) throws Exception {
        LOGGER.info("GateControllerServiceImpl.inGateRecordImportExcel param:{}", dto);
        if (Objects.equals(dto, null))
            throw new BusinessException("传入参数不能为空!");
        if (StringUtils.isBlank(dto.getUserId()))
            throw new BusinessException("用户id不能为空!");
        if (StringUtils.isBlank(dto.getWhCode()))
            throw new BusinessException("仓库code不能为空!");
        if (!WhCodeEnum.UNLCN_XN_CQ.getValue().equals(dto.getWhCode()))
            throw new BusinessException("该仓库不支持此操作!");
        HashMap<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("orderBy", StringUtils.isBlank(dto.getOrder()) ? "dr_id desc" : dto.getOrder());
        paramMap.put("status", dto.getStatus());
        paramMap.put("type", StringUtils.isBlank(dto.getDepartureType()) ? WmsDepartureTypeEnum.TMS_FAILED.getValue() : dto.getDepartureType());
        paramMap.put("vehicle", dto.getVehicle());
        paramMap.put("startTime", dto.getStartDeparturTime());
        paramMap.put("endTime", dto.getEndDepartureTime());
        paramMap.put("inoutType", StringUtils.isBlank(dto.getDepartureInOutType()) ? "" : dto.getDepartureInOutType());
        paramMap.put("whCode", dto.getWhCode());
        List<WmsDepartureRegister> list = wmsDepartureRegisterExtMapper.selectAllRecords(paramMap);
        if (CollectionUtils.isEmpty(list))
            throw new BusinessException("未查询到数据");
        //1.导出excel头
        String[] hearders = new String[]{
                "车牌号", "开闸类型", "异常登记原因", "入场登记时间", "出入场类型"
        };
        //设置值
        HSSFWorkbook workbook = updateExportToExcel("板车出入场记录导出数据", hearders, list, "yyyy-MM-dd HH:mm:ss");
        //输出流--提供下载
        BufferedOutputStream bufferedOutputStream = null;
        BufferedInputStream bufferedInputStream = null;
        ByteArrayOutputStream bos = null;
        ByteArrayInputStream inputStream = null;
        ServletOutputStream outputStream = null;
        try {
            bos = new ByteArrayOutputStream(2048);
            workbook.write(bos);
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            response.setHeader("Content-disposition", BrowerEncodeingUtils.getContentDisposition("GateInboundRecordsImport.xls", request));
            inputStream = new ByteArrayInputStream(bos.toByteArray());
            outputStream = response.getOutputStream();
            bufferedOutputStream = new BufferedOutputStream(outputStream);
            bufferedInputStream = new BufferedInputStream(inputStream);
            byte[] bytes = new byte[2048];
            int len;
            while ((len = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, len);
            }
        } catch (IOException e) {
            LOGGER.error("GateControllerServiceImpl.inGateRecordImportExcel error ", e);
            throw new BusinessException("下载文件异常!");
        } finally {
            if (bufferedInputStream != null) {
                bufferedInputStream.close();
            }
            if (bufferedOutputStream != null) {
                bufferedOutputStream.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
            if (bos != null) {
                bos.close();
            }
            if (workbook != null) {
                workbook.close();
            }
        }

    }

    /**
     * @param title                 报表头
     * @param headers               报表列标题
     * @param WmsDepartureRegisters 导出的列表
     * @param pattern               日期格式
     * @Description 导出excel，利用了Java的反射原理
     */
    private HSSFWorkbook updateExportToExcel(String title, String[] headers,
                                             List<WmsDepartureRegister> WmsDepartureRegisters, String pattern) {
        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet(title);
        // 设置表格默认列宽度为15个字节
        sheet.setDefaultColumnWidth((short) 20);
        // 生成一个样式
        HSSFCellStyle style = workbook.createCellStyle();
        // 设置这些样式
        style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//上下居中
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // 生成一个字体
        HSSFFont font = workbook.createFont();
        font.setColor(HSSFColor.VIOLET.index);
        font.setFontHeightInPoints((short) 12);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 把字体应用到当前的样式
        style.setFont(font);
        // 生成并设置另一个样式
        HSSFCellStyle style2 = workbook.createCellStyle();
        style2.setFillForegroundColor(HSSFColor.WHITE.index);
        style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style2.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        // 生成另一个字体
        HSSFFont font2 = workbook.createFont();
        font2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
        // 把字体应用到当前的样式
        style2.setFont(font2);

        //// 声明一个画图的顶级管理器
        //HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
        //// 定义注释的大小和位置,详见文档
        //HSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0,
        //        0, 0, 0, (short) 4, 2, (short) 6, 5));
        //// 设置注释内容
        //comment.setString(new HSSFRichTextString("可以在POI中添加注释！"));
        //// 设置注释作者，当鼠标移动到单元格上是可以在状态栏中看到该内容.
        //comment.setAuthor("leno");

        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);
        for (short i = 0; i < headers.length; i++) {
            HSSFCell cell = row.createCell(i);
            cell.setCellStyle(style);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            cell.setCellValue(text);
        }

        // 遍历集合数据，产生数据行
        Iterator<WmsDepartureRegister> iterator = WmsDepartureRegisters.iterator();
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        int index = 0;
        while (iterator.hasNext()) {
            index++;
            row = sheet.createRow(index);//创建行
            WmsDepartureRegister next = iterator.next();
            //对应头  设置cell的值
            for (short i = 0; i < headers.length; i++) {
                HSSFCell cell = row.createCell(i);
                cell.setCellStyle(style2);
                //  "车牌号", "开闸类型", "异常登记原因", "入场登记时间", "出入场类型"

                switch (i) {
                    case 0: {
                        cell.setCellValue(updateSetCellValue(next.getDrVehiclePlate()));
                        break;
                    }
                    case 1: {
                        Byte drDepartureType = next.getDrDepartureType();
                        if (drDepartureType != null) {
                            WmsDepartureTypeEnum byValue = WmsDepartureTypeEnum.getByValue(drDepartureType);
                            if (byValue != null) {
                                cell.setCellValue(updateSetCellValue(byValue.getText()));
                            }
                        }
                        break;
                    }
                    case 2: {
                        cell.setCellValue(updateSetCellValue(next.getDrDepartureReason()));
                        break;
                    }
                    case 3: {
                        cell.setCellValue(updateSetCellValue(getFormatDate(next.getDrDepartureTime())));
                        break;
                    }
                    case 4: {
                        if (StringUtils.isNotBlank(next.getInOutType())) {
                            if (WmsGateControllerTypeEnum.GATE_IN.getCode().equals(next.getInOutType()))
                                cell.setCellValue(updateSetCellValue(WmsGateControllerTypeEnum.GATE_IN.getText()));
                            if (WmsGateControllerTypeEnum.GATE_OUT.getCode().equals(next.getInOutType()))
                                cell.setCellValue(updateSetCellValue(WmsGateControllerTypeEnum.GATE_OUT.getText()));
                        }
                        break;
                    }
                    default:
                        break;
                }
            }
        }
        return workbook;
    }

    /**
     * 判断字符串设置值--非空过滤
     *
     * @return 返回值
     */
    private String updateSetCellValue(String value) {
        if (StringUtils.isNotBlank(value)) {
            return value;
        }
        return "";
    }

    /**
     * 时间格式化--非空过滤
     *
     * @param date 日期
     * @return 返回值
     */
    private String getFormatDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (date != null) {
            return sdf.format(date);
        }
        return "";
    }
}
